/*
 *  Copyright (c) 2019-2020, Medvish
 *  <p>
 *  Licensed under the GNU Lesser General Public License 3.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *  <p>
 * https://www.gnu.org/licenses/lgpl.html
 *  <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.kw.common.feign.exception;

import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.kw.common.core.exception.BusinessException;
import com.kw.common.core.util.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.stream.Collectors;


@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {



	/**
	 * todo 全局异常 有bug. 暂时这样 如果再有bug就不作用在oauth2 server
	 * 阅读AuthorizationEndpoint源码 无用户会抛出
	 * InsufficientAuthenticationException
	 * 本身即使报出异常  也会跳转页面到登陆
	 * 这时候会被全局拦截 直接输出json  导致无法跳转页面
	 * @param e the e
	 * @return R
	 */
	@ExceptionHandler(Exception.class)
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	public R exception(HttpServletRequest request, Exception e) throws Exception {
		Tracer.trace(e);
		log.error("全局异常信息 ex={}", e.getMessage(), e);
		return R.failed("系统异常");
	}


//	/**
//	 * 处理业务校验过程中碰到的非法参数异常 该异常基本由{@link org.springframework.util.Assert}抛出
//	 * @see Assert#hasLength(String, String)
//	 * @see Assert#hasText(String, String)
//	 * @see Assert#isTrue(boolean, String)
//	 * @see Assert#isNull(Object, String)
//	 * @see Assert#notNull(Object, String)
//	 * @param exception 参数校验异常
//	 * @return API返回结果对象包装后的错误输出结果
//	 */
	@ExceptionHandler(IllegalArgumentException.class)
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	public R handleIllegalArgumentException(IllegalArgumentException exception) {
		log.error("非法参数,ex = {}", exception.getMessage(), exception);
		return R.failed(exception.getMessage());
	}
//




//	@ExceptionHandler({IllegalArgumentException.class})
//	@ResponseStatus(HttpStatus.OK)
//	public R businessExceptionExceptionHandler(IllegalArgumentException e) {
//		R r  = new R();
//		return r.failed(e.getMessage());
//	}

	@ExceptionHandler({BusinessException.class})
	//@important
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	// 注意 feign 会拦截http状态码 如果是500会直接报错 导致前置应用无法获取错误信息
//	@ResponseStatus(HttpStatus.OK)
	public R businessExceptionExceptionHandler(BusinessException e) {
		return R.failed(e.getMessage());
	}


	@ExceptionHandler({AccessDeniedException.class})
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	public R FlowExceptionHandler(AccessDeniedException e) {
		R r  = new R();
		return r.setCode(401).setMsg("不允许访问");
	}




	@ExceptionHandler({BlockException.class,FlowException.class})
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	public R FlowExceptionHandler(Exception e) {
		R r  = new R();
		return r.setCode(9999).setMsg("接口限流");
	}





	/**
	 * validation Exception
	 *
	 * @param e
	 * @return R
	 */
	@ExceptionHandler({MethodArgumentNotValidException.class, BindException.class})
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	public R bodyValidExceptionHandler(Exception e) {
		List<FieldError> fieldErrors = null;
		if(e instanceof  BindException){
			fieldErrors = ((BindException)e).getBindingResult().getFieldErrors();
		}
		if(e instanceof  MethodArgumentNotValidException){
			fieldErrors = ((MethodArgumentNotValidException)e).getBindingResult().getFieldErrors();
		}
		log.warn(fieldErrors.stream().map(FieldError::getDefaultMessage).collect(Collectors.joining(",")));
		return R.failed(fieldErrors.get(0).getDefaultMessage());

	}

}
